﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BoyActionController : MonoBehaviour {

	BoyController bc;
	CharacterController cc;
	Animator m_Animator;
	Rigidbody2D rb;
	public Collider2D m_PushCollider;

	bool m_Pull;
	bool m_Push;
	bool m_Climb;
	float m_PullPenalty;
	float m_PushPenalty;
	Collider2D m_PullObject;
	public Transform m_PullCheck;
	public float m_PullCheckArea;

	public float ClimbSpeed = 1f;
	public Transform m_ClimbCheck;
	public Transform m_ClimbCheckBot;
	public LayerMask m_ClimbableLayer;
	public float m_ClimbCheckLength;
	[SerializeField] LayerMask m_ObstacleCheck;

	float ClimbMovement;

	public Transform m_PushCheck;
	public Vector2 m_PushCheckArea;

	bool pullHandOnLeft;
	Vector3 distanceToPull = Vector3.zero;

	[SerializeField] private BoolEvent OnPushBirdEvent;

	private void Awake() {
		rb = GetComponent<Rigidbody2D>();
		bc = GetComponent<BoyController>();
		cc = GetComponent<CharacterController>();
		if (OnPushBirdEvent == null)
			OnPushBirdEvent = new BoolEvent();
	}

	private void Start() {

		m_Animator = bc.m_Animator;
	}

	void Update() {

		bc.Movement(m_PullPenalty, m_Climb);

		CheckPull();

		if (!m_Pull && !m_Push)
			ClimbTheLadder();

	}

	private void FixedUpdate() {
	}

	/// <summary>
	///  爬梯子
	///  Tag:untagged 
	///  Layer:Climbable
	/// </summary>
	/// <returns>是否跳过pull行为判断</returns>
	bool ClimbTheLadder() {
		if (m_Animator.GetBool("JumpFix") || !bc.Controllable) {
			m_Animator.SetBool("Climbing", false);
			return false;
		}

		RaycastHit2D rh = Physics2D.Raycast(m_ClimbCheck.position, Vector2.right, m_ClimbCheckLength, m_ClimbableLayer);
		RaycastHit2D rh_bot = Physics2D.Raycast(m_ClimbCheckBot.position, Vector2.right, m_ClimbCheckLength, m_ClimbableLayer);

		ClimbMovement = InputReader.VerticalRaw;


		if (!rh && rh_bot && m_Climb && ClimbMovement > 0) {
			m_Climb = false;
			bc.ClimbOpenLadder();
		}

		if (rh) {
			if (ClimbMovement > 0 && !m_Climb) {
				m_Climb = true;
			}
		} else if (rh_bot) { //如果，
			m_Climb = true;
			if (ClimbMovement > 0) {

				m_Animator.SetBool("Climbing", true);
				ClimbMovement = 0;
				m_Animator.speed = 0;
			}

		} else {
			ClimbOver();
			return false;
		}

		if (m_Climb)
			OnPushBirdEvent.Invoke(true);

		//为了在地面爬楼梯
		if (cc.Grounded && ClimbMovement < 0) {
			ClimbOver();
		}

		if (m_Climb && ClimbMovement != 0) {

			RaycastHit2D obstacle = Physics2D.Raycast(m_ClimbCheck.position, Vector2.up, m_ClimbCheckLength, m_ObstacleCheck);

			if (ClimbMovement > 0 && obstacle) {
				m_Animator.speed = 0;
				return true;
			}

			m_Animator.speed = 1;
			if (!m_Animator.GetBool("Climbing")) {
				m_Animator.SetBool("Climbing", true);
				m_Animator.SetBool("Jumping", false);
			}
			m_Animator.SetBool("Falling", false);
			Vector3 newPos = transform.position;
			if (!rh)
				newPos.x = rh_bot.collider.bounds.center.x;
			else
				newPos.x = rh.collider.bounds.center.x;
			transform.position = newPos;
			transform.Translate(Vector3.up * ClimbMovement * Time.deltaTime * ClimbSpeed);

			rb.bodyType = RigidbodyType2D.Static;

			return true;
		} else if (m_Climb && ClimbMovement == 0) {
			m_Animator.speed = 0;
			if (InputReader.Jump) {
				m_Climb = false;
				if (InputReader.HorizontalRaw != 0) {
					m_Animator.SetBool("Climbing", false);
					bc.Jump(2 * transform.localScale.x);
				} else {
					rb.bodyType = RigidbodyType2D.Dynamic;
				}
			}
			return true;
		} else if (cc.Grounded) {  //上楼梯后退出爬楼梯状态
			ClimbOver();
		}

		return false;
	}
	/// <summary>
	/// 攀爬结束行为
	/// </summary>
	void ClimbOver() {
		rb.bodyType = RigidbodyType2D.Dynamic;
		m_Climb = false;
		m_Animator.SetBool("Climbing", false);
		m_Animator.speed = 1;
	}
	/// <summary>
	/// 检测推拉行为
	/// </summary>
	void CheckPull() {
		//行为判断 非jumpfix 和 功能按下情况进入
		if (InputReader.Pull && !bc.JumpFixing && cc.Grounded) {
			//检测可拖物体
			Collider2D[] drawable = Physics2D.OverlapCircleAll(m_PullCheck.position, m_PullCheckArea);
			foreach (var c2d in drawable) {
				if (c2d.tag == TagAndLayersConfigs.Tag.Box) {
					m_PullObject = c2d;
					break;
				}
			}
			if (m_PullObject != null) {

				pullHandOnLeft = bc.m_CC.m_FacingRight;

				Pull(true);

				Box box = m_PullObject.GetComponent<Box>();
				if (box != null)
					m_PullPenalty = box.PullPenatly;

				if (Vector3.Distance(Vector3.zero, distanceToPull) < .1f) {
					distanceToPull = m_PullObject.transform.position - m_PullCheck.position;
				}

				if (pullHandOnLeft && bc.m_Movement > 0 || !pullHandOnLeft && bc.m_Movement < 0) {
					m_PullPenalty = 0;
					m_Animator.speed = 1;
					Push(true);
				} else {
					if (bc.m_Movement != 0) {
						m_Animator.speed = 1 - m_PullPenalty;
						m_PullObject.gameObject.transform.position = m_PullCheck.position + distanceToPull;
					}
				}
				if (bc.m_Movement == 0) {
					m_Animator.speed = 0;
				}
			}

		} else {
			Pull(false);
		}

		if (!m_Pull && cc.Grounded) {
			Collider2D[] drawable = Physics2D.OverlapBoxAll(m_PushCheck.position, m_PushCheckArea, 0);
			foreach (var c2d in drawable) {
				if (c2d.tag == TagAndLayersConfigs.Tag.Box) {
					m_PullObject = c2d;
					break;
				}
			}
			if (m_PullObject != null && m_PullObject.tag == TagAndLayersConfigs.Tag.Box && bc.m_Movement != 0) {
				Push(true);
			} else {
				Push(false);
			}

		} else if (m_PullObject == null) {
			m_Pull = false;
			Pull(false);
		}
	}

	void Push(bool push) {
		if (!push) {
			m_PullObject = null;
			bc.m_Animator.speed = 1;
		}

		m_Animator.SetBool("Pulling", false);
		m_Animator.SetBool("Pushing", push);
		m_Push = push;
		m_PushCollider.enabled = push;
		if (!m_Pull)
			OnPushBirdEvent.Invoke(push);
	}
	void Pull(bool pull) {
		if (!pull) {
			m_PullObject = null;
			distanceToPull = Vector3.zero;
			bc.m_Animator.speed = 1;
			m_PullPenalty = 0;
		}
		bc.m_Animator.SetBool("Pulling", pull);
		bc.m_Animator.SetBool("Pushing", false);
		m_Pull = pull;
		m_PushCollider.enabled = pull;
		OnPushBirdEvent.Invoke(pull);

	}

	private void OnDrawGizmos() {

		Gizmos.color = Color.cyan;
		Gizmos.DrawWireSphere(m_PullCheck.position, m_PullCheckArea);
		Gizmos.DrawWireCube(m_PushCheck.position, m_PushCheckArea * Vector3.one);

		Gizmos.DrawLine(m_ClimbCheck.position, m_ClimbCheck.position + m_ClimbCheckLength * Vector3.right);
		Gizmos.DrawLine(m_ClimbCheckBot.position, m_ClimbCheckBot.position + m_ClimbCheckLength * Vector3.right);

	}

}
